package main

import (
	"context"
	"fmt"
	"math/rand"
	"time"
)

func main() {
	//testTimeout() //超时控制  timeout和deadline底层实现相同
	//testDeadline() //截止时间
	//testCancelFunc() //取消函数
	//testTransferValue() //值传递（安全上下文传值）
	testComplexTimeout() //父子timeout，以时间短的为准
	//testComplexCancelFunc() //父可以结束自己和子的，子只可以结束自己的
}

func testComplexCancelFunc() {
	exitCh := make(chan int)
	pCtx, pCancel := context.WithCancel(context.Background())
	defer pCancel()

	cCtx, cCancel := context.WithCancel(pCtx)
	defer cCancel()
	go worker(pCtx, exitCh, "父-pCtx")

	go worker(cCtx, exitCh, "子-cCtx")

	time.Sleep(2 * time.Second)
	fmt.Println("主协程-调度命令：[pCancel]")
	pCancel() // 同时停止所有worker

	//fmt.Println("主协程-调度命令：[cCancel]")
	//cCancel() // 同时停止所有worker

	<-exitCh
	<-exitCh
	fmt.Println("所有任务结束-主协程-退出~")
}

// testControlTimeout
//
//	@Description:  超时控制
func testTimeout() {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	fmt.Printf("context: %T \n", ctx) // *context.timerCtx
	result := make(chan string)
	go databaseQuery(ctx, result)
	select {
	case <-ctx.Done():
		fmt.Println("查询超时!!")
	case res := <-result:
		fmt.Println("查询结果：", res)
	}

}

// testDeadline
//
//	@Description: 测试截止时间
func testDeadline() {
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
	defer cancel()
	fmt.Printf("context: %T \n", ctx) // *context.timerCtx
	deadline, ok := ctx.Deadline()
	if ok {
		fmt.Println("task will end at:", deadline)
	}

	resultCh := make(chan string)
	errCh := make(chan error)
	go processLargeFile(ctx, "xxx.txt", resultCh, errCh)
	select {
	case <-ctx.Done():
		fmt.Println("截止时间到了,at:", time.Now())
		fmt.Println("清理临时文件~~~")
	case res := <-resultCh:
		fmt.Println("处理结果:", res)
	case err := <-errCh:
		fmt.Println("处理错误:", err)

	}
}

// 模拟处理大文件（带进度报告）
func processLargeFile(ctx context.Context, filename string, result chan<- string, errCh chan<- error) {
	defer close(result)
	defer close(errCh)
	// 模拟初始化操作
	fmt.Println("初始化文件处理器...")
	time.Sleep(1 * time.Second)

	// 检查截止时间
	if ctx.Err() != nil {
		errCh <- ctx.Err()
		return
	}

	// 模拟分块处理文件
	for i := 1; i <= 10; i++ {
		select {
		case <-ctx.Done():
			errCh <- fmt.Errorf("处理被取消，进度 %d/10", i)
			return
		default:
			// 模拟处理每个数据块需要500ms
			time.Sleep(500 * time.Millisecond)
			fmt.Printf("正在处理第 %d/10 个数据块...\n", i)
		}
	}
	// 完成处理
	result <- "文件处理完成，结果已保存"
}

func databaseQuery(ctx context.Context, result chan string) {
	intn := rand.Intn(6) + 1
	fmt.Printf("查询耗时：%d秒\n", intn)
	time.Sleep(time.Second * time.Duration(intn))
	select {
	case <-ctx.Done():
		fmt.Println("查询被取消")
		return
	default:
		result <- "success"
	}
}

// testCancelFunc
//
//	@Description: 取消函数
func testCancelFunc() {
	exitCh := make(chan int)
	defer close(exitCh)
	rootCtx, rootCancel := context.WithCancel(context.Background())
	defer rootCancel()
	fmt.Printf("context: %T \n", rootCtx) // *context.cancelCtx

	go worker(rootCtx, exitCh, "Worker1")
	go worker(rootCtx, exitCh, "Worker2")

	time.Sleep(2 * time.Second)
	fmt.Println("主协程-调度命令：[同时停止所有worker]")
	rootCancel() // 同时停止所有worker

	<-exitCh
	<-exitCh
	fmt.Println("所有任务结束-主协程-退出~")

}
func worker(ctx context.Context, exist chan int, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "退出")
			exist <- 1
			return
		default:
			fmt.Println(name, "运行中")
			time.Sleep(500 * time.Millisecond)
		}
	}
}

type parentKey struct {
	name     string
	createAt time.Time
}
type subKey struct {
	name     string
	createAt time.Time
}

// testTransferValue
//
//	@Description:  值传递（安全上下文传值）
func testTransferValue() {
	//传递值
	ctx := context.WithValue(context.Background(), parentKey{}, "PARENT-REQ-12345")
	fmt.Printf("context: %T \n", ctx) // *context.valueCtx
	//获取值
	processParentRequest(ctx)

	//使用子context传递值
	subCtx := context.WithValue(ctx, subKey{}, "SUB-REQ-12345")
	//从子context获取值
	processSubRequest(subCtx)

}
func processParentRequest(ctx context.Context) {
	contextValue, ok := ctx.Value(parentKey{}).(string)
	if ok {
		fmt.Println("parentV:", contextValue)
	}
}

func processSubRequest(ctx context.Context) {
	pv, ok := ctx.Value(parentKey{}).(string)
	if ok {
		fmt.Println("parentV:", pv)
	}
	sv, ok := ctx.Value(subKey{}).(string)
	if ok {
		fmt.Println("subV:", sv)
	}
}

// complexOperation
//
//	@Description: 父子timeout，以时间短的为准
func testComplexTimeout() {
	existCh := make(chan string)
	defer close(existCh)

	// 父操作
	pCtx, pCancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer pCancel()

	// 子操作
	cCtx, cCancel := context.WithTimeout(pCtx, 3*time.Second)
	defer cCancel()

	go func() {
		select {
		case <-cCtx.Done():
			existCh <- "[子操作超时]"
		case <-pCtx.Done():
			existCh <- "[父超时触发]"
		}
	}()
	es := <-existCh

	fmt.Println(es, "所有任务结束-主协程-退出~")
}
